#ifndef __GRAPHICS_DRIVER_H__
#define __GRAPHICS_DRIVER_H__

#pragma once

#include "EngineCompileConfig.h"
#include "Utilities.h"

namespace Nezha
{

	enum GraphicsCaps
	{
		GC_AUTOMIPMAP,
		GC_ANISOTROPY,
		GC_CUBEMAPPING,
		GC_STENCIL,
		GC_STENCIL_SEPARATE,			// also called two side stencil
		GC_STENCIL_WRAP,
		GC_SCISSOR,
		GC_HARDWARE_OCCLUSION,
		GC_USER_CLIP_PLANES,
		GC_INFINITE_FAR_PLANE,
		GC_HARDWARE_RT,
		GC_FLOAT_TEXTURE,
		GC_NON_POWER_2,
		GC_3D_TEXTURE,
		GC_VERTEX_TEXTURE,
		GC_MIPMAP_LOD_BIAS,
		GC_POINT_SPRITES,
		GC_MULTI_RENDERTARGET,
		GC_GET_COMPILED_SHADER_BUFFER,
		GC_RTT_DEPTHBUFFER_LESSEQUAL,

		GC_NUM
	};

	enum GraphicsCapsDX
	{
		// FIXME only DX?
		GC_TEXTURE_DXT,
	};

	enum GraphicsCapsGL
	{
		GC_FBO,
		GC_PBUFFER,
		GC_SHADER_SEPARATE,
		GC_TEXTURE_ETC,
		GC_TEXTURE_PVR
	};

	struct NEZHA_ENGINE_ENTRY DriverVersion
	{
		int mVersionMajor;
		int mVersionMinor;
		int mVersionRelease;
		int mVersionBuild;

		DriverVersion()
			:mVersionMajor(0)
			,mVersionMinor(0)
			,mVersionRelease(0)
			,mVersionBuild(0)
		{
		}

		_string toString() const
		{
			_stringStream _stream;
			_stream << mVersionMajor << "." << mVersionMinor << "." << mVersionRelease << "." << mVersionBuild;
			return _stream.str();
		}

		void fromString(const _string& str)
		{
			StringArray tokens;
			StringUtil::Split(str, tokens, ".");
			if(tokens.size() > 0)
			{
				mVersionMajor = StringUtil::Convert<int>(tokens[0], 0);
				if(tokens.size() > 1)
				{
					mVersionMinor = StringUtil::Convert<int>(tokens[1], 0);
					if(tokens.size() > 2)
					{
						mVersionRelease = StringUtil::Convert<int>(tokens[2], 0);
						if(tokens.size() > 3)
						{
							mVersionBuild = StringUtil::Convert<int>(tokens[3], 0);
						}
					}
				}
			}
		}

		bool operator < (const DriverVersion& v) const
		{
			return getFloatValue() < v.getFloatValue();
		}

		bool operator > (const DriverVersion& v) const
		{
			return getFloatValue() > v.getFloatValue();
		}

		bool operator == (const DriverVersion& v) const
		{
			return getFloatValue() == v.getFloatValue();
		}

		f64 getFloatValue() const
		{
			return 1000000.0 * (f64)mVersionMajor + 10000.0 * (f64)mVersionMinor
				+ 10.0 * (f64)mVersionRelease + 0.0001 * (f64)mVersionBuild;
		}
	};

	/** just for graphics capabilities query. */
	class NEZHA_ENGINE_ENTRY GraphicsDriver 
	{
	public:
		GraphicsDriver();
		virtual ~GraphicsDriver(){}

		const DriverVersion& getVersion() const
		{
			return mInfo.mVersion;
		}
		
		const _string& getVendorName() const
		{
			return mInfo.mVendorName;
		}

		const _string& getDeviceName() const
		{
			return mInfo.mDeviceName;
		}

		bool hasCapability(GraphicsCaps gc) const
		{
			return (mInfo.mCapsFlag & (1 << gc)) != 0;
		}

		bool hasCapabilityDX(GraphicsCapsDX gc) const
		{
			return (mInfo.mCapsFlagDX & (1 << gc)) != 0;
		}

		bool hasCapabilityGL(GraphicsCapsGL gc) const
		{
			return (mInfo.mCapsFlagGL & (1 << gc)) != 0;
		}

		u8 getNumTextureUnits() const
		{
			return mInfo.mNumTexureUnits;
		}

		u8 getStencilBufferBits() const
		{
			return mInfo.mStencilBufferBits;
		}

		u8 getNumVertexTextures() const
		{
			return mInfo.mNumVertexTextures;
		}

		u8 getNumRenderTargetsSupport() const
		{
			return mInfo.mNumRenderTargetsSupport;
		}

		u16 getNumVSConstFloat() const
		{
			return mInfo.mNumVSConstFloat;
		}

		u16 getNumVSConstInt() const
		{
			return mInfo.mNumVSConstInt;
		}

		u16 getNumVSConstBool() const
		{
			return mInfo.mNumVSConstBool;
		}

		u16 getNumPSConstFloat() const
		{
			return mInfo.mNumPSConstFloat;
		}

		u16 getNumPSConstInt() const
		{
			return mInfo.mNumPSConstInt;
		}

		u16 getNumPSConstBool() const
		{
			return mInfo.mNumPSConstBool;
		}

		void printLog();

		template <typename T>
			static void SetCapsFlag(T flag, u32 bits)
		{
			flag |= (1 << bits);
		}

		// allow child to expose these data for purpose.
		class NEZHA_ENGINE_ENTRY InfoStruct
		{
		public:
			_string mDeviceName;
			_string mVendorName;

			u32 mCapsFlag;
			u32 mCapsFlagDX;
			u32 mCapsFlagGL;

			DriverVersion mVersion;

			u16 mNumVSConstFloat;
			u16 mNumVSConstInt;
			u16 mNumVSConstBool;
			u16 mNumPSConstFloat;
			u16 mNumPSConstInt;
			u16 mNumPSConstBool;

			u8 mNumTexureUnits;
			u8 mStencilBufferBits;
			u8 mNumVertexTextures;
			u8 mNumRenderTargetsSupport;

			InfoStruct();
		};

	protected:
		InfoStruct mInfo;
	};

}//end namespace Nezha

#endif //end __GRAPHICS_DRIVER_H__